package com.example.util;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.regex.Pattern;

/**
 * 安全工具类 - 输入验证和安全检查
 */
@Slf4j
@Component
public class SecurityUtils {

    // SQL注入检测模式 - 增强版
    private static final Pattern SQL_INJECTION_PATTERN = Pattern.compile(
        "(?i)(union|select|insert|update|delete|drop|create|alter|exec|execute|script|javascript|vbscript|onload|onerror|alert|confirm|prompt|" +
        "information_schema|sys\\.tables|sys\\.columns|pg_tables|sqlite_master|dual|waitfor|delay|benchmark|sleep|" +
        "char\\(|ascii\\(|substring\\(|mid\\(|left\\(|right\\(|concat\\(|group_concat\\(|" +
        "0x[0-9a-f]+|\\\\x[0-9a-f]+|--|/\\*|\\*/|;\\s*drop|;\\s*delete|;\\s*insert|;\\s*update|" +
        "load_file\\(|into\\s+outfile|into\\s+dumpfile|extractvalue\\(|updatexml\\(|" +
        "sp_executesql|xp_cmdshell|sp_oacreate|sp_oamethod)",
        Pattern.CASE_INSENSITIVE
    );

    // XSS攻击检测模式
    private static final Pattern XSS_PATTERN = Pattern.compile(
        "(?i)<script[^>]*>.*?</script>|javascript:|vbscript:|onload=|onerror=|onclick=|onmouseover=|<iframe|<object|<embed",
        Pattern.CASE_INSENSITIVE | Pattern.DOTALL
    );

    // 路径遍历攻击检测模式
    private static final Pattern PATH_TRAVERSAL_PATTERN = Pattern.compile(
        "(\\.\\./|\\.\\.\\\\|%2e%2e%2f|%2e%2e%5c)",
        Pattern.CASE_INSENSITIVE
    );

    // 文件名安全检测模式
    private static final Pattern SAFE_FILENAME_PATTERN = Pattern.compile(
        "^[a-zA-Z0-9._-]+$"
    );

    // 用户名安全检测模式
    private static final Pattern SAFE_USERNAME_PATTERN = Pattern.compile(
        "^[a-zA-Z0-9_-]{3,20}$"
    );

    // 邮箱格式检测模式
    private static final Pattern EMAIL_PATTERN = Pattern.compile(
        "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"
    );

    // 手机号格式检测模式
    private static final Pattern PHONE_PATTERN = Pattern.compile(
        "^1[3-9]\\d{9}$"
    );

    /**
     * 检测SQL注入攻击
     */
    public boolean containsSqlInjection(String input) {
        if (!StringUtils.hasText(input)) {
            return false;
        }
        
        boolean detected = SQL_INJECTION_PATTERN.matcher(input).find();
        if (detected) {
            log.warn("检测到SQL注入攻击尝试: {}", sanitizeLogInput(input));
        }
        return detected;
    }

    /**
     * 检测XSS攻击
     */
    public boolean containsXss(String input) {
        if (!StringUtils.hasText(input)) {
            return false;
        }
        
        boolean detected = XSS_PATTERN.matcher(input).find();
        if (detected) {
            log.warn("检测到XSS攻击尝试: {}", sanitizeLogInput(input));
        }
        return detected;
    }

    /**
     * 检测路径遍历攻击
     */
    public boolean containsPathTraversal(String input) {
        if (!StringUtils.hasText(input)) {
            return false;
        }
        
        boolean detected = PATH_TRAVERSAL_PATTERN.matcher(input).find();
        if (detected) {
            log.warn("检测到路径遍历攻击尝试: {}", sanitizeLogInput(input));
        }
        return detected;
    }

    /**
     * 验证文件名安全性
     */
    public boolean isSafeFilename(String filename) {
        if (!StringUtils.hasText(filename)) {
            return false;
        }
        
        // 检查文件名长度
        if (filename.length() > 255) {
            return false;
        }
        
        // 检查是否包含危险字符
        if (containsPathTraversal(filename)) {
            return false;
        }
        
        // 检查文件名格式
        return SAFE_FILENAME_PATTERN.matcher(filename).matches();
    }

    /**
     * 验证用户名安全性
     */
    public boolean isSafeUsername(String username) {
        if (!StringUtils.hasText(username)) {
            return false;
        }
        
        return SAFE_USERNAME_PATTERN.matcher(username).matches();
    }

    /**
     * 验证邮箱格式
     */
    public boolean isValidEmail(String email) {
        if (!StringUtils.hasText(email)) {
            return false;
        }
        
        return EMAIL_PATTERN.matcher(email).matches();
    }

    /**
     * 验证手机号格式
     */
    public boolean isValidPhone(String phone) {
        if (!StringUtils.hasText(phone)) {
            return false;
        }
        
        return PHONE_PATTERN.matcher(phone).matches();
    }

    /**
     * 清理HTML标签
     */
    public String sanitizeHtml(String input) {
        if (!StringUtils.hasText(input)) {
            return input;
        }
        
        return input
            .replaceAll("<script[^>]*>.*?</script>", "")
            .replaceAll("<[^>]+>", "")
            .replaceAll("javascript:", "")
            .replaceAll("vbscript:", "")
            .replaceAll("onload=", "")
            .replaceAll("onerror=", "")
            .replaceAll("onclick=", "")
            .replaceAll("onmouseover=", "");
    }

    /**
     * 转义SQL特殊字符
     */
    public String escapeSql(String input) {
        if (!StringUtils.hasText(input)) {
            return input;
        }
        
        return input
            .replace("'", "''")
            .replace("\"", "\\\"")
            .replace("\\", "\\\\")
            .replace("%", "\\%")
            .replace("_", "\\_");
    }

    /**
     * 验证密码强度
     */
    public boolean isStrongPassword(String password) {
        if (!StringUtils.hasText(password)) {
            return false;
        }
        
        // 密码长度至少8位
        if (password.length() < 8) {
            return false;
        }
        
        // 必须包含大写字母
        if (!password.matches(".*[A-Z].*")) {
            return false;
        }
        
        // 必须包含小写字母
        if (!password.matches(".*[a-z].*")) {
            return false;
        }
        
        // 必须包含数字
        if (!password.matches(".*[0-9].*")) {
            return false;
        }
        
        // 必须包含特殊字符
        if (!password.matches(".*[!@#$%^&*()_+\\-=\\[\\]{};':\"\\\\|,.<>\\/?].*")) {
            return false;
        }
        
        return true;
    }

    /**
     * 生成安全的随机字符串
     */
    public String generateSecureRandomString(int length) {
        String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
        StringBuilder sb = new StringBuilder();
        java.security.SecureRandom random = new java.security.SecureRandom();
        
        for (int i = 0; i < length; i++) {
            sb.append(chars.charAt(random.nextInt(chars.length())));
        }
        
        return sb.toString();
    }

    /**
     * 验证IP地址格式
     */
    public boolean isValidIpAddress(String ip) {
        if (!StringUtils.hasText(ip)) {
            return false;
        }
        
        String[] parts = ip.split("\\.");
        if (parts.length != 4) {
            return false;
        }
        
        try {
            for (String part : parts) {
                int num = Integer.parseInt(part);
                if (num < 0 || num > 255) {
                    return false;
                }
            }
            return true;
        } catch (NumberFormatException e) {
            return false;
        }
    }

    /**
     * 清理日志输入，防止日志注入
     */
    public String sanitizeLogInput(String input) {
        if (!StringUtils.hasText(input)) {
            return input;
        }
        
        return input
            .replaceAll("[\r\n\t]", "_")
            .replaceAll("[\\p{Cntrl}]", "")
            .substring(0, Math.min(input.length(), 100)); // 限制长度
    }

    /**
     * 验证URL安全性
     */
    public boolean isSafeUrl(String url) {
        if (!StringUtils.hasText(url)) {
            return false;
        }
        
        // 检查协议
        if (!url.startsWith("http://") && !url.startsWith("https://")) {
            return false;
        }
        
        // 检查是否包含危险字符
        if (containsXss(url) || containsPathTraversal(url)) {
            return false;
        }
        
        return true;
    }

    /**
     * 限制字符串长度
     */
    public String limitLength(String input, int maxLength) {
        if (!StringUtils.hasText(input)) {
            return input;
        }

        if (input.length() <= maxLength) {
            return input;
        }

        return input.substring(0, maxLength);
    }

    /**
     * 检测命令注入攻击
     */
    public boolean containsCommandInjection(String input) {
        if (!StringUtils.hasText(input)) {
            return false;
        }

        String[] commandPatterns = {
            ";", "|", "&", "$", "`", "$(", "&&", "||",
            "exec", "system", "shell_exec", "passthru", "popen",
            "eval", "base64_decode", "file_get_contents", "include",
            "require", "fopen", "fwrite", "file_put_contents",
            "curl_exec", "proc_open", "shell", "cmd", "powershell",
            "/bin/", "/usr/bin/", "wget", "nc ", "netcat", "telnet"
        };

        String lowerInput = input.toLowerCase();
        for (String pattern : commandPatterns) {
            if (lowerInput.contains(pattern)) {
                log.warn("检测到命令注入攻击尝试: {}", sanitizeLogInput(input));
                return true;
            }
        }

        return false;
    }

    /**
     * 检测LDAP注入攻击
     */
    public boolean containsLdapInjection(String input) {
        if (!StringUtils.hasText(input)) {
            return false;
        }

        String[] ldapPatterns = {
            "*", "(", ")", "\\", "/", "=", "!", "&", "|",
            "objectClass", "cn=", "ou=", "dc=", "uid=",
            "\\2a", "\\28", "\\29", "\\5c", "\\2f"
        };

        for (String pattern : ldapPatterns) {
            if (input.contains(pattern)) {
                log.warn("检测到LDAP注入攻击尝试: {}", sanitizeLogInput(input));
                return true;
            }
        }

        return false;
    }

    /**
     * 检测NoSQL注入攻击
     */
    public boolean containsNoSqlInjection(String input) {
        if (!StringUtils.hasText(input)) {
            return false;
        }

        String[] nosqlPatterns = {
            "$where", "$ne", "$in", "$nin", "$gt", "$gte", "$lt", "$lte",
            "$regex", "$exists", "$type", "$mod", "$all", "$size",
            "javascript:", "function(", "this.", "db.", "sleep(",
            "true", "false", "null", "undefined", "NaN"
        };

        String lowerInput = input.toLowerCase();
        for (String pattern : nosqlPatterns) {
            if (lowerInput.contains(pattern.toLowerCase())) {
                log.warn("检测到NoSQL注入攻击尝试: {}", sanitizeLogInput(input));
                return true;
            }
        }

        return false;
    }

    /**
     * 检测XML注入攻击
     */
    public boolean containsXmlInjection(String input) {
        if (!StringUtils.hasText(input)) {
            return false;
        }

        String[] xmlPatterns = {
            "<!DOCTYPE", "<!ENTITY", "SYSTEM", "PUBLIC",
            "&xxe;", "&lt;", "&gt;", "&amp;", "&quot;",
            "file://", "http://", "ftp://", "gopher://",
            "<?xml", "<!--", "-->"
        };

        String lowerInput = input.toLowerCase();
        for (String pattern : xmlPatterns) {
            if (lowerInput.contains(pattern.toLowerCase())) {
                log.warn("检测到XML注入攻击尝试: {}", sanitizeLogInput(input));
                return true;
            }
        }

        return false;
    }

    /**
     * 检测模板注入攻击
     */
    public boolean containsTemplateInjection(String input) {
        if (!StringUtils.hasText(input)) {
            return false;
        }

        String[] templatePatterns = {
            "{{", "}}", "${", "<%", "%>", "#{", "#{",
            "freemarker", "velocity", "thymeleaf", "mustache",
            "handlebars", "jinja2", "twig", "smarty",
            "__import__", "getattr", "exec", "eval"
        };

        String lowerInput = input.toLowerCase();
        for (String pattern : templatePatterns) {
            if (lowerInput.contains(pattern.toLowerCase())) {
                log.warn("检测到模板注入攻击尝试: {}", sanitizeLogInput(input));
                return true;
            }
        }

        return false;
    }

    /**
     * 检测反序列化攻击
     */
    public boolean containsDeserializationAttack(String input) {
        if (!StringUtils.hasText(input)) {
            return false;
        }

        String[] deserializationPatterns = {
            "rO0AB", "aced0005", "java.lang.Runtime", "java.lang.ProcessBuilder",
            "javax.script.ScriptEngineManager", "com.sun.org.apache.xalan",
            "org.apache.commons.collections", "org.springframework.context",
            "serialVersionUID", "readObject", "writeObject"
        };

        for (String pattern : deserializationPatterns) {
            if (input.contains(pattern)) {
                log.warn("检测到反序列化攻击尝试: {}", sanitizeLogInput(input));
                return true;
            }
        }

        return false;
    }

    /**
     * 综合安全检查
     */
    public boolean isSecureInput(String input) {
        if (!StringUtils.hasText(input)) {
            return true;
        }

        // 检查是否为安全的URL路径
        if (isSafeUrlPath(input)) {
            return true;
        }

        // 检查是否为User-Agent（更宽松的检查）
        if (isUserAgentHeader(input)) {
            return isSecureUserAgent(input);
        }

        return !containsSqlInjection(input) &&
               !containsXss(input) &&
               !containsPathTraversal(input) &&
               !containsCommandInjection(input) &&
               !containsLdapInjectionStrict(input) &&
               !containsNoSqlInjection(input) &&
               !containsXmlInjection(input) &&
               !containsTemplateInjection(input) &&
               !containsDeserializationAttack(input);
    }

    /**
     * 检查是否为User-Agent字符串
     */
    private boolean isUserAgentHeader(String input) {
        if (!StringUtils.hasText(input)) {
            return false;
        }

        // 常见的浏览器User-Agent特征
        String lowerInput = input.toLowerCase();
        return lowerInput.contains("mozilla") ||
               lowerInput.contains("chrome") ||
               lowerInput.contains("firefox") ||
               lowerInput.contains("safari") ||
               lowerInput.contains("edge") ||
               lowerInput.contains("opera") ||
               lowerInput.contains("webkit") ||
               lowerInput.contains("gecko");
    }

    /**
     * 对User-Agent进行安全检查（更宽松）
     */
    private boolean isSecureUserAgent(String userAgent) {
        if (!StringUtils.hasText(userAgent)) {
            return false;
        }

        // 只检查明显的恶意User-Agent
        String[] maliciousPatterns = {
            "sqlmap", "nmap", "nikto", "dirb", "gobuster", "masscan",
            "nessus", "openvas", "burp", "zap", "w3af", "skipfish",
            "<script", "javascript:", "vbscript:", "onload=", "onerror="
        };

        String lowerUserAgent = userAgent.toLowerCase();
        for (String pattern : maliciousPatterns) {
            if (lowerUserAgent.contains(pattern)) {
                log.warn("检测到恶意User-Agent: {}", sanitizeLogInput(userAgent));
                return false;
            }
        }

        return true;
    }

    /**
     * 检查是否为安全的URL路径
     */
    private boolean isSafeUrlPath(String input) {
        // 常见的安全URL路径模式
        String[] safePatterns = {
            "^/actuator/.*",
            "^/api/.*",
            "^/swagger-ui/.*",
            "^/v3/api-docs.*",
            "^/h2-console/.*",
            "^/static/.*",
            "^/css/.*",
            "^/js/.*",
            "^/images/.*",
            "^/fonts/.*",
            "^/favicon.ico$",
            "^/error$"
        };

        for (String pattern : safePatterns) {
            if (input.matches(pattern)) {
                return true;
            }
        }

        return false;
    }

    /**
     * 严格的LDAP注入检测（排除正常URL路径）
     */
    private boolean containsLdapInjectionStrict(String input) {
        if (!StringUtils.hasText(input)) {
            return false;
        }

        // 如果是URL路径，使用更宽松的检查
        if (input.startsWith("/")) {
            String[] strictLdapPatterns = {
                "objectClass", "cn=", "ou=", "dc=", "uid=",
                "\\2a", "\\28", "\\29", "\\5c", "\\2f"
            };

            for (String pattern : strictLdapPatterns) {
                if (input.contains(pattern)) {
                    log.warn("检测到LDAP注入攻击尝试: {}", sanitizeLogInput(input));
                    return true;
                }
            }
            return false;
        }

        // 对于非URL路径，使用原来的严格检查
        return containsLdapInjection(input);
    }

    /**
     * 检测JWT伪造攻击
     */
    public boolean isValidJwtFormat(String token) {
        if (!StringUtils.hasText(token)) {
            return false;
        }

        // JWT应该有3个部分，用.分隔
        String[] parts = token.split("\\.");
        if (parts.length != 3) {
            return false;
        }

        // 检查每个部分是否为有效的Base64
        for (String part : parts) {
            if (!isValidBase64(part)) {
                return false;
            }
        }

        return true;
    }

    /**
     * 检查是否为有效的Base64
     */
    private boolean isValidBase64(String input) {
        try {
            java.util.Base64.getUrlDecoder().decode(input);
            return true;
        } catch (IllegalArgumentException e) {
            return false;
        }
    }
}
